<!--
 * @Author: weidewei
 * @Date: 2025-10-27 15:02:46
 * @LastEditors: weidewei
 * @LastEditTime: 2025-10-27 17:55:06
 * @Description: 
 * @FilePath: \2025-front-face\review-knowledge\20251027\复习vue3响应式原理.html
-->
<script>
  // 1.数据劫持: Proxy
  // 2. 依赖收集: track trigger

  function isObject(obj) {
    return obj !== null && !Array.isArray(obj) && typeof obj === "object";
  }

  let activeFn;

  // 代理的地图
  let proxyMap = new WeakMap();

  // 存储最外层的依赖地图
  let depsMap = new WeakMap();

  // 收集依赖
  function track(target,key) {
    // 内层的Map 对象的Map
    let targetMap = depsMap.get(target);
    if(!targetMap) {
      targetMap = new Map();
      depsMap.set(target,targetMap);
    }
    let objKeysMap = targetMap.get(key);
    if(!objKeysMap) {
      objKeysMap = new Set();
      targetMap.set(key,objKeysMap);
    }
    objKeysMap.add(activeFn);
  }

  // 派发更新
  function trigger(target,key) {
    // 一层一层取出依赖，没有就return掉
    let targetMap = depsMap.get(target);
    if(!targetMap) return;
    let objKeyMap = targetMap.get(key);
    if(!objKeyMap) return;
    objKeyMap.forEach(fn=>fn());
  }

  function reactive(obj) {
    if (!isObject(obj)) return obj;
    // 以当前对象作为键，看一下是否被代理过！！
    let result = proxyMap.get(obj);
    if (result) return result;
    result = new Proxy(obj, {
      get(target, key) {
        let value = Reflect.get(target, key);
        // 如果代理的对象里面还有对象，则继续代理
        value = reactive(value);
        console.log(`读取${key}的值为：${value}`);
        track(target,key);
        return value;
      },
      set(target, key, value) {
        value = reactive(value);
        console.log(`设置${key}的值为：${value}`);
        trigger(target,key);
        return Reflect.set(target, key, value);
      },
    });
    proxyMap.set(obj, result);
    return result;
  }

  function effect(fn) {
    function updateWrapper() {
      activeFn = updateWrapper;
      fn();
      activeFn = null;
    }
    updateWrapper();
  }

  const state = reactive({
    name: "张三",
    age: 20,
    province: {
      city: {
        name: "北京",
      },
    },
  });
  effect(() => {
    console.log("依赖的副作用函数重新执行了~~", state.name);
  });

  // state.name = "李四";
</script>
